/*
 * Gabi_Project.c
 *
 *  Created on: 25/09/2012
 *      Author: Emeson Santana
 */
#define ITERACOES 10000000
#define DESVIO_VALIDACAO 0.1
#define ITERACOES_SEM_EVOLUCAO 0.01*ITERACOES/10 // "/10" por causa da verificacao da validacao que ocorre a cada 10 iteracoes

#define CAMADA_ENTRADA 3
#define CAMADA_ESCONDIDA 5
#define CAMADA_SAIDA 1
#define TAMANHO_SERIE 94
#define TAMANHO_SERIE_VALIDACAO 47
#define TAMANHO_SERIE_TESTE 47
#define MEDIA_O 0.6877182323 // sum( SERIE[ CAMADA_ENTRADA : TAMANHO_SERIE ] ) / (CAMADA_ENTRADA - TAMANHO_SERIE)
#define MEDIA_O_VALIDACAO 0.5478818142
#define MEDIA_O_TESTE 0.7262592148
//======================================================================================================
#define TAMANHO_POPULACAO 10
#define PROBABILIDADE_MUTACAO 0.1
#define PESO_W 0.8

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "Functions.h"
#include "MersenneTwister.h"

struct individuo{
	double W[CAMADA_ESCONDIDA];
	double V[CAMADA_ENTRADA*CAMADA_ESCONDIDA];
	double Bj[CAMADA_ESCONDIDA];
	double Bk[1];
	double fitness[3];
}POPULACAO[TAMANHO_POPULACAO], LISTA_FILHOS[4], LISTA_MUTACAO[4], LISTA_PAIS[2], Melhor_Validacao;

void Criar_Individuo( struct individuo *individuo );
void RedeNeural( struct individuo individuo, double *y, long tamanho_serie, const double serie[] );
double LogSig( double alfa );
double MSE( double y[], long tamanho_serie, const double serie[] );
double MAPE( double y[], long tamanho_serie, const double serie[] );
double THEIL( double y[], long tamanho_serie, const double serie[] );
double ARV( double y[], long tamanho_serie, const double serie[], double media_O );
double POCID( double y[], long tamanho_serie, const double serie[] );
void fitness( struct individuo *individuo, int NUM, unsigned long _TAMANHO_SERIE, const double _SERIE[], double _MEDIA_O  );
double Media_Fitness();
//=====================================================================================================
void Criar_Populacao( struct individuo *populacao );
void Selecao_Roleta( struct individuo *populacao, struct individuo *lista_pais );
void Cruzamento( struct individuo *lista_pais,  struct individuo *lista_filhos);
void Mutacao( struct individuo *lista_filhos, struct individuo *lista_mutacao);
long Pior_Individuo( struct individuo *populacao );
long Melhor_Individuo( struct individuo *populacao );
void Selecao_Sobrevivencia(struct individuo *lista_filhos, struct individuo *lista_mutacao, struct individuo *populacao);

const double SERIE[TAMANHO_SERIE] = {0.492463301317329, 0.441125696608775, 0.0, 0.724762776471133, 0.825051268088656, 0.716803188469604, 0.889504234686193, 0.769982968567158, 0.698172886422356, 0.801543256363615, 0.657181587514917, 0.783028814403726, 0.498383751781349, 0.549385362236563, 0.669323724670088, 0.722445574723963, 0.797847319576879, 0.769206705981856, 0.806594756172446, 0.731702795703908, 0.710998598092943, 0.669752406993315, 0.780734784674028, 0.876956587225267, 0.498418509807556, 0.601313853390646, 0.710651017830867, 0.693978751259978, 0.745316355968532, 0.741886897382721, 0.769693318348762, 0.697663102037979, 0.797198503087671, 0.510317340779275, 0.69154568942545, 0.963828480726674, 0.548620685659997, 0.631252099964083, 0.837691603619469, 0.672556221107391, 0.813812839614881, 0.881533060675928, 0.741585661155589, 0.828550242726883, 0.725353662916662, 0.738109858534833, 0.876099222578814, 0.884221014702645, 0.661572684825804, 0.75434185677376, 0.849428230468886, 0.698682670806734, 0.941061973560728, 0.924829975321801, 0.934515878624972, 0.999142635353547, 0.692078645827299, 0.892725145114759, 0.804520860608729, 1.0, 0.801705460485917, 0.804972714949427, 0.897429064661515, 0.837529399497167, 0.9004298409241, 0.759740936844666, 0.789169399033727, 0.596216009546871, 0.615182305847459, 0.772647750576404, 0.644993106324802, 0.641772195896236, 0.565930182711358, 0.528611648573183, 0.474713535934006, 0.462814704962288, 0.500005793004368, 0.516423167383068, 0.615274993917345, 0.486670296949404, 0.413597339852394, 0.484862879586611, 0.351160338774895, 0.503806003869727, 0.340848790999988, 0.295524324825341, 0.515102362387181, 0.446154024400134, 0.256027621044826, 0.415671235416111, 0.597826464761154, 0.420108676761942, 0.524290067314711, 0.601684605670193};
const double SERIE_VALIDACAO[TAMANHO_SERIE_VALIDACAO] = {0.555027748490922, 0.613815156816628, 0.407781163466997, 0.529283637079862, 0.629131860365423, 0.380310736754295, 0.444728945325625, 0.458481537695079, 0.489601557159574, 0.604893930090023, 0.481630383149309, 0.464552606272665, 0.512866262701162, 0.518740369130238, 0.375340339006616, 0.462316506586646, 0.534821749255599, 0.426608427662754, 0.555549118884036, 0.483912826870272, 0.482754225996686, 0.560253038430791, 0.480494954293196, 0.500063723048047, 0.518079966632295, 0.531751456940599, 0.487875241857932, 0.512113172133332, 0.506482371887708, 0.581930460775567, 0.742582057906872, 0.639292790026764, 0.690873700918771, 0.589426608427663, 0.471063943182213, 0.672301328915202, 0.553370949241696, 0.647935952543708, 0.546268725886619, 0.514326099801879, 0.502809607118444, 0.592856067013474, 0.713060907647924, 0.529422669184693, 0.804184866355389, 0.717139182722944, 0.665314965647484};
const double SERIE_TESTE[TAMANHO_SERIE_TESTE] = {0.78056099454299, 0.934434776563822, 0.779344463625726, 0.695079422089884, 0.710199163490169, 0.768268239274252, 0.811634669972541, 0.796769820764445, 0.863319854943171, 0.732282096140701, 0.660726906188087, 0.654180811252332, 0.635596853240027, 0.577979631796642, 0.757655455272213, 0.456708878358494, 0.522181413724786, 0.701254764746093, 0.684316019974279, 0.651794093452746, 0.662511151533408, 0.836382384632318, 0.80739419077522, 0.813360985274183, 0.786805853251613, 0.694210471434695, 0.792946437881614, 0.562384864038187, 0.575372779831076, 0.870549524394341, 0.725585383091379, 0.794302000903709, 0.800929197900615, 0.671316518172655, 0.755338253525043, 0.8827843496194, 0.784674027644217, 0.738874535111399, 0.823267022743335, 0.63760123275133, 0.649546407757991, 0.844040736406715, 0.584328764583889, 0.938733185804822, 0.844341972633847, 0.625864605901913, 0.772010520095932};
int NUM_FITNESS;
FILE *file;

int main(void) {
	char string[80];
	long i, j, x, count = 0, posicao, num_arq = 0, ver_iteracoes = 0;
	double y[TAMANHO_SERIE - CAMADA_ENTRADA], y_teste[TAMANHO_SERIE_TESTE - CAMADA_ENTRADA], y_val[TAMANHO_SERIE_VALIDACAO - CAMADA_ENTRADA];

	for(x=1 +num_arq;x<6 +num_arq;x++){
		for(i=0;i<20;i++){
			sprintf(string,"simulacao_pig_%d_fitness_%d.txt", (int)x, (int)(i +1));
			file = fopen(string , "w");
			fprintf(file,"Melhor Fitness | Media dos Fitness | Fitness de Validacao |\n\n" );
			fflush(file);
			NUM_FITNESS = i;
			Criar_Populacao(POPULACAO);
			count = 0;
			ver_iteracoes = 0;
			for(j=0;j<ITERACOES;j++){
				/* ============== Inicio do AG ======================================= */
				Selecao_Roleta(POPULACAO, LISTA_PAIS);
				Cruzamento(LISTA_PAIS, LISTA_FILHOS);
				Mutacao(LISTA_FILHOS, LISTA_MUTACAO);
				Selecao_Sobrevivencia(LISTA_FILHOS, LISTA_MUTACAO, POPULACAO);
				/* ==============   Fim do AG  ======================================= */
				if(j == 299){
					posicao = Melhor_Individuo(POPULACAO);
					fitness( &POPULACAO[posicao], 1, TAMANHO_SERIE_VALIDACAO, SERIE_VALIDACAO, MEDIA_O_VALIDACAO );
					Melhor_Validacao = POPULACAO[posicao];
					count += 10;
					fprintf(file," %.10f | %.10f | %.10f |\n", POPULACAO[posicao].fitness[0], Media_Fitness(), POPULACAO[posicao].fitness[1] );
					fflush(file);
				}
				else if(j == 299 + count){
					posicao = Melhor_Individuo(POPULACAO);
					fitness(&POPULACAO[posicao], 1, TAMANHO_SERIE_VALIDACAO, SERIE_VALIDACAO, MEDIA_O_VALIDACAO);
					if( (Melhor_Validacao.fitness[1] - POPULACAO[posicao].fitness[1]) >=
							(Melhor_Validacao.fitness[1]*DESVIO_VALIDACAO)){
						fprintf(file," %.10f | %.10f | %.10f |\n", POPULACAO[posicao].fitness[0], Media_Fitness(), POPULACAO[posicao].fitness[1] );
						fflush(file);
						break;
					}
					else{
						if(Melhor_Validacao.fitness[1] < POPULACAO[posicao].fitness[1]){
							Melhor_Validacao = POPULACAO[posicao];
							ver_iteracoes = 0;
						}
						else{
							ver_iteracoes++;
						}
						fprintf(file," %.10f | %.10f | %.10f |\n", POPULACAO[posicao].fitness[0], Media_Fitness(), POPULACAO[posicao].fitness[1] );
						fflush(file);
						count += 10;
					}
				}
				else{
					posicao = Melhor_Individuo(POPULACAO);
					fprintf(file," %.10f | %.10f | x |\n", POPULACAO[posicao].fitness[0], Media_Fitness() );
					fflush(file);
				}
				if(ver_iteracoes >= ITERACOES_SEM_EVOLUCAO){
					break;
				}
			}
			fclose(file);
			sprintf(string,"melhor_ind_simulacao_pig_%d_fitness_%d.txt", (int)x, (int)(i +1));
			fopen(string, "w");
			fprintf(file,"Melhor Individuo\n\n");
			fflush(file);

			fprintf(file,"W's\n");
			fflush(file);
			for(j=0;j<CAMADA_ESCONDIDA;j++){
				fprintf(file,"%.10f\n", Melhor_Validacao.W[j]);
				fflush(file);
			}
			fprintf(file,"\nBj's\n");
			fflush(file);
			for(j=0;j<CAMADA_ESCONDIDA;j++){
				fprintf(file,"%.10f\n", Melhor_Validacao.Bj[j]);
				fflush(file);
			}
			fprintf(file,"\nV's\n");
			fflush(file);
			for(j=0;j<CAMADA_ENTRADA*CAMADA_ESCONDIDA;j++){
				fprintf(file,"%.10f\n", Melhor_Validacao.V[j]);
				fflush(file);
			}

			fprintf(file,"\nBk's\n");
			fflush(file);
			fprintf(file,"%.10f\n\n", Melhor_Validacao.Bk[0]);
			fflush(file);

			fprintf(file,"Fitness = %.10f\n", Melhor_Validacao.fitness[0]);
			fflush(file);
			fprintf(file,"Fitness de Validacao = %.10f\n", Melhor_Validacao.fitness[1]);
			fflush(file);
			fitness(&Melhor_Validacao, 2, TAMANHO_SERIE_TESTE, SERIE_TESTE, MEDIA_O_TESTE);
			fprintf(file,"Fitness de Teste = %.10f\n", Melhor_Validacao.fitness[2]);
			fflush(file);

			RedeNeural( Melhor_Validacao, y, TAMANHO_SERIE, SERIE);
			RedeNeural( Melhor_Validacao, y_val, TAMANHO_SERIE_VALIDACAO, SERIE_VALIDACAO);
			RedeNeural( Melhor_Validacao, y_teste, TAMANHO_SERIE_TESTE, SERIE_TESTE);
			fprintf(file, "\nMetricas\nARV | MSE | MAPE | THEIL | POCID\n");
			fprintf(file, "\nTreinamento\n");
			fprintf(file, "%.10f | %.10f | %.10f | %.10f | %.10f\n", ARV( y, TAMANHO_SERIE, SERIE, MEDIA_O ), MSE( y, TAMANHO_SERIE, SERIE ), MAPE( y, TAMANHO_SERIE, SERIE ), THEIL( y, TAMANHO_SERIE, SERIE ), POCID( y, TAMANHO_SERIE, SERIE ));

			fprintf(file, "\nValidacao\n");
			fprintf(file, "%.10f | %.10f | %.10f | %.10f | %.10f\n", ARV( y_val, TAMANHO_SERIE_VALIDACAO, SERIE_VALIDACAO, MEDIA_O_VALIDACAO ), MSE( y_val, TAMANHO_SERIE_VALIDACAO, SERIE_VALIDACAO ), MAPE( y_val, TAMANHO_SERIE_VALIDACAO, SERIE_VALIDACAO ), THEIL( y_val, TAMANHO_SERIE_VALIDACAO, SERIE_VALIDACAO ), POCID( y_val, TAMANHO_SERIE_VALIDACAO, SERIE_VALIDACAO ));

			fprintf(file, "\nTeste\n");
			fprintf(file, "%.10f | %.10f | %.10f | %.10f | %.10f\n", ARV( y_teste, TAMANHO_SERIE_TESTE, SERIE_TESTE, MEDIA_O_TESTE ), MSE( y_teste, TAMANHO_SERIE_TESTE, SERIE_TESTE ), MAPE( y_teste, TAMANHO_SERIE_TESTE, SERIE_TESTE ), THEIL( y_teste, TAMANHO_SERIE_TESTE, SERIE_TESTE ), POCID( y_teste, TAMANHO_SERIE_TESTE, SERIE_TESTE ));

			fflush(file);

			fprintf(file, "\nSeries Previstas\nTreinamento\n\n");

			for(j=0; j < TAMANHO_SERIE - CAMADA_ENTRADA; j++){
				fprintf(file, "%.10f;\n", y[j]);
			}

			fprintf(file, "\nValidacao\n\n");

			for(j=0; j < TAMANHO_SERIE_VALIDACAO - CAMADA_ENTRADA; j++){
				fprintf(file, "%.10f;\n", y_val[j]);
			}

			fprintf(file, "\nTeste\n\n");

			for(j=0; j < TAMANHO_SERIE_TESTE - CAMADA_ENTRADA; j++){
				fprintf(file, "%.10f;\n", y_teste[j]);
			}

			fclose(file);
		}
	}
	return EXIT_SUCCESS;
}

double
Media_Fitness()
{
	long i;
	double sum = 0;

	for(i=0;i<TAMANHO_POPULACAO;i++){
		sum += POPULACAO[i].fitness[0];
	}

	return sum / TAMANHO_POPULACAO;
}

void
RedeNeural( struct individuo individuo, double *y, long tamanho_serie, const double serie[] )
{
	double sum_i=0, sum_j=0;
	long x = 0, i, j, pos;

	while(tamanho_serie >= (x + CAMADA_ENTRADA + CAMADA_SAIDA)){
		sum_j = 0;
		for(j=0;j<CAMADA_ESCONDIDA;j++){
			pos = j*CAMADA_ENTRADA;
			sum_i = 0;
			for(i=0;i<CAMADA_ENTRADA;i++){
				sum_i += individuo.V[pos + i] * serie[x + i];
			}
			sum_i -= individuo.Bj[j];
			sum_j += individuo.W[j]*LogSig( sum_i );
		}
		*(y + x) = sum_j - individuo.Bk[0];

		x++;
	}
}

double
LogSig( double alfa )
{
	return 1 / (1 + exp(-alfa));
}

void
Criar_Individuo( struct individuo *individuo )
{
	long i;

	for(i=0;i<CAMADA_ESCONDIDA;i++){
		individuo->W[i] = random_uniform(-10.0,10.0);
		individuo->Bj[i] = random_uniform(-10.0,10.0);
	}
	for(i=0;i<CAMADA_ENTRADA*CAMADA_ESCONDIDA;i++){
		individuo->V[i] = random_uniform(-10.0,10.0);
	}

	individuo->Bk[0] = random_uniform(-10.0,10.0);

	fitness( individuo, 0, TAMANHO_SERIE, SERIE, MEDIA_O );
}

double
MSE( double y[], long tamanho_serie, const double serie[] )
{
	long i;
	double sum = 0;

	for(i=CAMADA_ENTRADA;i<tamanho_serie;i++){
		sum += pow(serie[i] - y[i - CAMADA_ENTRADA], 2.0);
	}

	return sum / (tamanho_serie - CAMADA_ENTRADA);
}

double
MAPE( double y[], long tamanho_serie, const double serie[] )
{
	long i;
	double sum = 0;

	for(i=CAMADA_ENTRADA;i<tamanho_serie;i++){
		if(serie[i] != 0) sum += fabs((serie[i] - y[i - CAMADA_ENTRADA])/serie[i]);
	}

	return sum / (tamanho_serie - CAMADA_ENTRADA);
}

double
THEIL( double y[], long tamanho_serie, const double serie[] )
{
	long i;
	double sum_1 = 0, sum_2 = 0;

	for(i=CAMADA_ENTRADA;i<tamanho_serie -1;i++){
		sum_1 += pow( serie[i] - y[i - CAMADA_ENTRADA], 2.0 );
		sum_2 += pow( serie[i] - serie[i +1], 2.0 );
	}

	return sum_1 / sum_2;
}

double
ARV( double y[], long tamanho_serie, const double serie[], double media_O )
{
	long i;
	double sum_1 = 0, sum_2 = 0;

	for(i=CAMADA_ENTRADA;i<tamanho_serie -1;i++){
		sum_1 += pow( serie[i] - y[i - CAMADA_ENTRADA], 2.0 );
		sum_2 += pow( serie[i] - media_O, 2.0 );
	}

	return sum_1 / sum_2;
}

double
POCID( double y[], long tamanho_serie, const double serie[] )
{
	long i;
	double sum = 0;

	for(i=CAMADA_ENTRADA +1;i<tamanho_serie;i++){
		if((y[i -CAMADA_ENTRADA] - y[(i-1) -CAMADA_ENTRADA])*(serie[i] - serie[i -1]) > 0) sum += 1;
	}

	return sum / (tamanho_serie - (CAMADA_ENTRADA +1));
}

void
fitness( struct individuo *individuo, int NUM,unsigned long _TAMANHO_SERIE, const double _SERIE[], double _MEDIA_O  )
{
	double Y_k[_TAMANHO_SERIE - CAMADA_ENTRADA];

	RedeNeural( *individuo, Y_k, _TAMANHO_SERIE, _SERIE);

	if(NUM_FITNESS == 0) individuo->fitness[NUM] = 1 / (1 + ARV(Y_k, _TAMANHO_SERIE, _SERIE, _MEDIA_O)) ;
	else if(NUM_FITNESS == 1) individuo->fitness[NUM] = 1 / (1 + MSE(Y_k, _TAMANHO_SERIE, _SERIE)) ;
	else if(NUM_FITNESS == 2) individuo->fitness[NUM] = 1 / (1 + MAPE(Y_k, _TAMANHO_SERIE, _SERIE)) ;
	else if(NUM_FITNESS == 3) individuo->fitness[NUM] = 1 / (1 + THEIL(Y_k, _TAMANHO_SERIE, _SERIE)) ;
	else if(NUM_FITNESS == 4) individuo->fitness[NUM] = 1 / (1 + MSE(Y_k, _TAMANHO_SERIE, _SERIE) + ARV(Y_k, _TAMANHO_SERIE, _SERIE, _MEDIA_O)) ;
	else if(NUM_FITNESS == 5) individuo->fitness[NUM] = 1 / (1 + MSE(Y_k, _TAMANHO_SERIE, _SERIE) + MAPE(Y_k, _TAMANHO_SERIE, _SERIE)) ;
	else if(NUM_FITNESS == 6) individuo->fitness[NUM] = 1 / (1 + MSE(Y_k, _TAMANHO_SERIE, _SERIE) + THEIL(Y_k, _TAMANHO_SERIE, _SERIE)) ;
	else if(NUM_FITNESS == 7) individuo->fitness[NUM] = 1 / (1 + ARV(Y_k, _TAMANHO_SERIE, _SERIE, _MEDIA_O) + MAPE(Y_k, _TAMANHO_SERIE, _SERIE)) ;
	else if(NUM_FITNESS == 8) individuo->fitness[NUM] = 1 / (1 + ARV(Y_k, _TAMANHO_SERIE, _SERIE, _MEDIA_O) + THEIL(Y_k, _TAMANHO_SERIE, _SERIE)) ;
	else if(NUM_FITNESS == 9) individuo->fitness[NUM] = 1 / (1 + MAPE(Y_k, _TAMANHO_SERIE, _SERIE) + THEIL(Y_k, _TAMANHO_SERIE, _SERIE)) ;
	else if(NUM_FITNESS == 10) individuo->fitness[NUM] = POCID(Y_k, _TAMANHO_SERIE, _SERIE) / (1 + ARV(Y_k, _TAMANHO_SERIE, _SERIE, _MEDIA_O)) ;
	else if(NUM_FITNESS == 11) individuo->fitness[NUM] = POCID(Y_k, _TAMANHO_SERIE, _SERIE) / (1 + MSE(Y_k, _TAMANHO_SERIE, _SERIE)) ;
	else if(NUM_FITNESS == 12) individuo->fitness[NUM] = POCID(Y_k, _TAMANHO_SERIE, _SERIE) / (1 + MAPE(Y_k, _TAMANHO_SERIE, _SERIE)) ;
	else if(NUM_FITNESS == 13) individuo->fitness[NUM] = POCID(Y_k, _TAMANHO_SERIE, _SERIE) / (1 + THEIL(Y_k, _TAMANHO_SERIE, _SERIE)) ;
	else if(NUM_FITNESS == 14) individuo->fitness[NUM] = POCID(Y_k, _TAMANHO_SERIE, _SERIE) / (1 + MSE(Y_k, _TAMANHO_SERIE, _SERIE) + ARV(Y_k, _TAMANHO_SERIE, _SERIE, _MEDIA_O)) ;
	else if(NUM_FITNESS == 15) individuo->fitness[NUM] = POCID(Y_k, _TAMANHO_SERIE, _SERIE) / (1 + MSE(Y_k, _TAMANHO_SERIE, _SERIE) + MAPE(Y_k, _TAMANHO_SERIE, _SERIE)) ;
	else if(NUM_FITNESS == 16) individuo->fitness[NUM] = POCID(Y_k, _TAMANHO_SERIE, _SERIE) / (1 + MSE(Y_k, _TAMANHO_SERIE, _SERIE) + THEIL(Y_k, _TAMANHO_SERIE, _SERIE)) ;
	else if(NUM_FITNESS == 17) individuo->fitness[NUM] = POCID(Y_k, _TAMANHO_SERIE, _SERIE) / (1 + ARV(Y_k, _TAMANHO_SERIE, _SERIE, _MEDIA_O) + MAPE(Y_k, _TAMANHO_SERIE, _SERIE)) ;
	else if(NUM_FITNESS == 18) individuo->fitness[NUM] = POCID(Y_k, _TAMANHO_SERIE, _SERIE) / (1 + ARV(Y_k, _TAMANHO_SERIE, _SERIE, _MEDIA_O) + THEIL(Y_k, _TAMANHO_SERIE, _SERIE)) ;
	else if(NUM_FITNESS == 19) individuo->fitness[NUM] = POCID(Y_k, _TAMANHO_SERIE, _SERIE) / (1 + MAPE(Y_k, _TAMANHO_SERIE, _SERIE) + THEIL(Y_k, _TAMANHO_SERIE, _SERIE)) ;
}

void
Criar_Populacao( struct individuo *populacao )
{
	int i;

	for(i=0;i<TAMANHO_POPULACAO;i++){
		Criar_Individuo((populacao +i));
	}
}

void
Selecao_Roleta( struct individuo *populacao, struct individuo *lista_pais )
{
	long i;
	struct individuo populacao_[TAMANHO_POPULACAO];

	for(i=0;i<TAMANHO_POPULACAO;i++){
		populacao_[i] = *(populacao + i);
	}

	for(i=0;i<2;i++){
		double prob[TAMANHO_POPULACAO - i];
		double roleta[TAMANHO_POPULACAO + 1 - i];
		double sum_fitness = 0.0;
		double acumulado = 0.0;
		double ponteiro;
		int j,x;

		for(j=0;j<TAMANHO_POPULACAO - i;j++){
			sum_fitness += populacao_[j].fitness[0];
		}
		for(j=0;j<TAMANHO_POPULACAO - i;j++){
			prob[j] = populacao_[j].fitness[0]/sum_fitness;
		}
		for(j=0;j<TAMANHO_POPULACAO+1 - i;j++){
			roleta[j] = acumulado;
			if(j == TAMANHO_POPULACAO) continue;
			acumulado += prob[j];
		}

		ponteiro = random_uniform(0,1);
		while( ponteiro == 0 ) ponteiro = random_uniform(0,1);

		for(j=1;j<TAMANHO_POPULACAO+1 - i;j++){
			if(roleta[j-1] < ponteiro && ponteiro <= roleta[j]){
				*(lista_pais +i) = populacao_[j-1];
				if(i == 0){
					for(x=j;x<TAMANHO_POPULACAO;x++){
						populacao_[x-1] = populacao_[x];
					}
				}
				break;
			}
		}
	}
}

void
Cruzamento( struct individuo *lista_pais,  struct individuo *lista_filhos)
{
	long i;

	for(i=0;i<CAMADA_ESCONDIDA;i++){
		(lista_filhos)->W[i] = (lista_pais->W[i] + (lista_pais +1)->W[i])/2 ;
		(lista_filhos)->Bj[i] = (lista_pais->Bj[i] + (lista_pais +1)->Bj[i])/2;
		(lista_filhos +1)->W[i] = (10 * (1 -PESO_W)) + (max(lista_pais->W[i], (lista_pais +1)->W[i]) *PESO_W);
		(lista_filhos +1)->Bj[i] = (10 * (1 -PESO_W)) + (max(lista_pais->Bj[i], (lista_pais +1)->Bj[i]) *PESO_W);
		(lista_filhos +2)->W[i] = (-10 * (1 -PESO_W)) + (min(lista_pais->W[i], (lista_pais +1)->W[i]) *PESO_W);
		(lista_filhos +2)->Bj[i] = (-10 * (1 -PESO_W)) + (min(lista_pais->Bj[i], (lista_pais +1)->Bj[i]) *PESO_W);
		(lista_filhos +3)->W[i] = ((lista_pais->W[i] + (lista_pais +1)->W[i]) *PESO_W);
		if( (lista_filhos +3)->W[i] > 10 ) (lista_filhos +3)->W[i] = fmod((lista_filhos +3)->W[i], 10.0);
		else if( (lista_filhos +3)->W[i] < -10 ) (lista_filhos +3)->W[i] = fmod((lista_filhos +3)->W[i], -10.0);
		(lista_filhos +3)->Bj[i] = ((lista_pais->Bj[i] + (lista_pais +1)->Bj[i]) *PESO_W);
		if( (lista_filhos +3)->Bj[i] > 10 ) (lista_filhos +3)->Bj[i] = fmod((lista_filhos +3)->Bj[i], 10.0);
		else if( (lista_filhos +3)->Bj[i] < -10 ) (lista_filhos +3)->Bj[i] = fmod((lista_filhos +3)->Bj[i], -10.0);
	}
	for(i=0;i<CAMADA_ENTRADA*CAMADA_ESCONDIDA;i++){
		(lista_filhos)->V[i] = (lista_pais->V[i] + (lista_pais +1)->V[i])/2;
		(lista_filhos +1)->V[i] = (10 * (1 -PESO_W)) + (max(lista_pais->V[i], (lista_pais +1)->V[i]) *PESO_W);
		(lista_filhos +2)->V[i] = (-10 * (1 -PESO_W)) + (min(lista_pais->V[i], (lista_pais +1)->V[i]) *PESO_W);
		(lista_filhos +3)->V[i] = ((lista_pais->V[i] + (lista_pais +1)->V[i]) *PESO_W);
		if( (lista_filhos +3)->V[i] > 10 ) (lista_filhos +3)->V[i] = fmod((lista_filhos +3)->V[i], 10.0);
		else if( (lista_filhos +3)->V[i] < -10 ) (lista_filhos +3)->V[i] = fmod((lista_filhos +3)->V[i], -10.0);
	}

	(lista_filhos)->Bk[0] = (lista_pais->Bk[i] + (lista_pais +1)->Bk[i])/2;
	(lista_filhos +1)->Bk[0] = (10 * (1 -PESO_W)) + (max(lista_pais->Bk[i], (lista_pais +1)->Bk[i]) *PESO_W);
	(lista_filhos +2)->Bk[0] = (-10 * (1 -PESO_W)) + (min(lista_pais->Bk[i], (lista_pais +1)->Bk[i]) *PESO_W);
	(lista_filhos +3)->Bk[0] = ((lista_pais->Bk[i] + (lista_pais +1)->Bk[i]) *PESO_W);
	if( (lista_filhos +3)->Bk[i] > 10 ) (lista_filhos +3)->Bk[i] = fmod((lista_filhos +3)->Bk[i], 10.0);
	else if( (lista_filhos +3)->Bk[i] < -10 ) (lista_filhos +3)->Bk[i] = fmod((lista_filhos +3)->Bk[i], -10.0);

	fitness( (lista_filhos), 0, TAMANHO_SERIE, SERIE, MEDIA_O );
	fitness( (lista_filhos +1), 0, TAMANHO_SERIE, SERIE, MEDIA_O );
	fitness( (lista_filhos +2), 0, TAMANHO_SERIE, SERIE, MEDIA_O );
	fitness( (lista_filhos +3), 0, TAMANHO_SERIE, SERIE, MEDIA_O );
}

void
Mutacao( struct individuo *lista_filhos, struct individuo *lista_mutacao)
{
	int i;
	long quant, posicao, j;
	struct individuo rand_individuo;

	Criar_Individuo( &rand_individuo );

	for(i=0;i<4;i++){
		*(lista_mutacao +i) = *(lista_filhos +i);
	}

	for(i=0;i<4;i++){

		quant = (long)random_uniform(0, CAMADA_ESCONDIDA+0.9);
		for(j=0;j<quant;j++){
			posicao = (long)random_uniform(0, CAMADA_ESCONDIDA -0.1);
			(lista_mutacao +i)->W[posicao] += rand_individuo.W[posicao];
			if( (lista_mutacao +i)->W[posicao] > 10 ) (lista_mutacao +i)->W[posicao] = fmod((lista_mutacao +i)->W[posicao], 10.0);
			else if( (lista_mutacao +i)->W[posicao] < -10 ) (lista_mutacao +i)->W[posicao] = fmod((lista_mutacao +i)->W[posicao], -10.0);
		}

		quant = (long)random_uniform(0, CAMADA_ESCONDIDA+0.9);
		for(j=0;j<quant;j++){
			posicao = (long)random_uniform(0, CAMADA_ESCONDIDA -0.1);
			(lista_mutacao +i)->Bj[posicao] += rand_individuo.Bj[posicao];
			if( (lista_mutacao +i)->Bj[posicao] > 10 ) (lista_mutacao +i)->Bj[posicao] = fmod((lista_mutacao +i)->Bj[posicao], 10.0);
			else if( (lista_mutacao +i)->Bj[posicao] < -10 ) (lista_mutacao +i)->Bj[posicao] = fmod((lista_mutacao +i)->Bj[posicao], -10.0);
		}

		quant = (long)random_uniform(0, CAMADA_ENTRADA*CAMADA_ESCONDIDA+0.9);
		for(j=0;j<quant;j++){
			posicao = (long)random_uniform(0, CAMADA_ENTRADA*CAMADA_ESCONDIDA -0.1);
			(lista_mutacao +i)->V[posicao] += rand_individuo.V[posicao];
			if( (lista_mutacao +i)->V[posicao] > 10 ) (lista_mutacao +i)->V[posicao] = fmod((lista_mutacao +i)->V[posicao], 10.0);
			else if( (lista_mutacao +i)->V[posicao] < -10 ) (lista_mutacao +i)->V[posicao] = fmod((lista_mutacao +i)->V[posicao], -10.0);
		}

		quant = (long)random_uniform(0, 1.9);
		for(j=0;j<quant;j++){
			(lista_mutacao +i)->Bk[0] += rand_individuo.Bk[0];
			if( (lista_mutacao +i)->Bk[0] > 10 ) (lista_mutacao +i)->Bk[0] = fmod((lista_mutacao +i)->Bk[0], 10.0);
			else if( (lista_mutacao +i)->Bk[0] < -10 ) (lista_mutacao +i)->Bk[0] = fmod((lista_mutacao +i)->Bk[0], -10.0);
		}
	}

	fitness( (lista_mutacao), 0, TAMANHO_SERIE, SERIE, MEDIA_O );
	fitness( (lista_mutacao +1), 0, TAMANHO_SERIE, SERIE, MEDIA_O );
	fitness( (lista_mutacao +2), 0, TAMANHO_SERIE, SERIE, MEDIA_O );
	fitness( (lista_mutacao +3), 0, TAMANHO_SERIE, SERIE, MEDIA_O );
}

long
Pior_Individuo( struct individuo *populacao )
{
	long i, posicao = 0;

	for(i=1;i<TAMANHO_POPULACAO;i++){
		if((populacao + i)->fitness[0] < (populacao + posicao)->fitness[0]) posicao = i;
	}
	return posicao;
}

long
Melhor_Individuo( struct individuo *populacao )
{
	long i, posicao = 0;

	for(i=1;i<TAMANHO_POPULACAO;i++){
		if((populacao + i)->fitness[0] > (populacao + posicao)->fitness[0]) posicao = i;
	}
	return posicao;
}

void
Selecao_Sobrevivencia(struct individuo *lista_filhos, struct individuo *lista_mutacao, struct individuo *populacao)
{
	long i, pior;
	float rand;

	for(i=0;i<4;i++){
		pior = Pior_Individuo( populacao );
		if((lista_filhos + i)->fitness[0] > (populacao + pior)->fitness[0]) *(populacao + pior) = *(lista_filhos + i);

	}

	for(i=0;i<4;i++){
		pior = Pior_Individuo( populacao );
		rand = random_uniform(0,1);
		if((lista_mutacao + i)->fitness[0] > (populacao + pior)->fitness[0]) *(populacao + pior) = *(lista_mutacao + i);
		else if(rand <= PROBABILIDADE_MUTACAO) *(populacao + pior) = *(lista_mutacao + i);
	}
}
